package com.yeskery.nut.aop.handler;

import com.yeskery.nut.aop.Execution;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.util.StringUtils;

import java.lang.reflect.Method;

/**
 * 基础的切入代理方法处理器
 * @author sprout
 * @version 1.0
 * 2022-08-28 13:13
 */
public abstract class BaseInjectProxyMethodHandler extends BaseApplicationSupportProxyMethodHandler {

    /**
     * 构建基础的切入代理方法处理器
     * @param applicationContext 应用上下文
     */
    public BaseInjectProxyMethodHandler(ApplicationContext applicationContext) {
        super(applicationContext);
    }

    /**
     * 获取目标对象
     * @param object 被代理对象
     * @param beanName bean名称
     * @param beanType bean类型
     * @return 目标对象
     */
    protected Object getTargetObject(Object object, String beanName, Class<?> beanType) {
        if (StringUtils.isEmpty(beanName) && void.class.equals(beanType)) {
            return object;
        } else {
            return StringUtils.isEmpty(beanName)
                    ? getApplicationContext().getBean(beanType)
                    : getApplicationContext().getBean(beanName);
        }
    }

    /**
     * 执行切入方法
     * @param object 被代理对象
     * @param beanName bean名称
     * @param beanType bean类型
     * @param methodName 方法名称
     * @throws Exception 发生的异常对象
     */
    protected void doInjectMethod(Object object, String beanName, Class<?> beanType, String methodName) throws Exception {
        invokeSpecifyMethod(getTargetObject(object, beanName, beanType), methodName, new Object[0]);
    }

    /**
     * 执行切入方法
     * @param object 被代理对象
     * @param beanName bean名称
     * @param beanType bean类型
     * @param methodName 方法名称
     * @param args 方法参数
     * @throws Exception 发生的异常对象
     */
    protected void doInjectMethod(Object object, String beanName, Class<?> beanType, String methodName, Object[] args) throws Exception {
        invokeSpecifyMethod(getTargetObject(object, beanName, beanType), methodName, args);
    }

    /**
     * 执行指定方法
     * @param object 被代理对象
     * @param methodName 方法名称
     * @throws Exception 发生的异常对象
     */
    private void invokeSpecifyMethod(Object object, String methodName, Object[] args) throws Exception {
        Method invokeMethod;
        try {
            invokeMethod = object.getClass().getMethod(methodName, Execution.class);
        } catch (NoSuchMethodException e) {
            invokeMethod = object.getClass().getMethod(methodName);
        }
        invokeMethod.invoke(object, args);
    }
}
